{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Quantum Tomography"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Introduction\n",
    "\n",
    "Quantum tomography is an experimental procedure to reconstruct a description of part of quantum system from the measurement outcomes of a specific set of experiments. In Qiskit we implement the following types of tomography:\n",
    "\n",
    "1. **Quantum state tomography**: Given a state-preparation circuit that prepares a system in a state, reconstruct a description of the density matrix $\\rho$ of the actual state obtained in the system.\n",
    "2. **Quantum process tomography**: Given a circuit, reconstruct a description of the quantum channel $\\mathcal{E}$ that describes the circuit's operator when running on the system.\n",
    "3. **Quantum gate set tomography**: Performs process tomography on a set of gates in a self-consistent manner, meaning quantum noises on gates used by the tomography process itself is also taken into account.\n",
    "\n",
    "This notebook gives examples for how to use the ``ignis.verification.tomography`` modules."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-10T22:02:05.692984Z",
     "start_time": "2019-12-10T22:02:02.719087Z"
    }
   },
   "outputs": [],
   "source": [
    "# Needed for functions\n",
    "import numpy as np\n",
    "import time\n",
    "from copy import deepcopy\n",
    "\n",
    "# Import Qiskit classes\n",
    "import qiskit\n",
    "import qiskit.quantum_info as qi\n",
    "from qiskit import QuantumRegister, QuantumCircuit, ClassicalRegister, Aer\n",
    "from qiskit.providers.aer import noise\n",
    "from qiskit.compiler import assemble\n",
    "\n",
    "# Tomography functions\n",
    "from qiskit.ignis.verification.tomography import state_tomography_circuits, StateTomographyFitter\n",
    "from qiskit.ignis.verification.tomography import process_tomography_circuits, ProcessTomographyFitter\n",
    "from qiskit.ignis.verification.tomography import gateset_tomography_circuits, GatesetTomographyFitter\n",
    "import qiskit.ignis.mitigation.measurement as mc\n",
    "\n",
    "# Auxiliary methods\n",
    "from qiskit.quantum_info import Choi, Kraus\n",
    "from qiskit.extensions import HGate, XGate"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Initial examples"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2-Qubit state tomography Example"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the below example we want to perform state tomography on a 2Q Bell state between qubits 3 and 5. To make the reference circuit we generate the expected statevector using ``statevector_simulator`` between qubits 0 and 1. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-10T22:02:05.715895Z",
     "start_time": "2019-12-10T22:02:05.695482Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "      ┌───┐     \n",
      "q0_0: ┤ H ├──■──\n",
      "      └───┘┌─┴─┐\n",
      "q0_1: ─────┤ X ├\n",
      "           └───┘\n",
      "Statevector([0.70710678+0.j, 0.        +0.j, 0.        +0.j,\n",
      "             0.70710678+0.j],\n",
      "            dims=(2, 2))\n"
     ]
    }
   ],
   "source": [
    "# Create the expected statevector\n",
    "q2 = QuantumRegister(2)\n",
    "bell = QuantumCircuit(q2)\n",
    "bell.h(q2[0])\n",
    "bell.cx(q2[0], q2[1])\n",
    "print(bell)\n",
    "\n",
    "target_state_bell = qi.Statevector.from_instruction(bell)\n",
    "print(target_state_bell)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-10T22:02:05.726381Z",
     "start_time": "2019-12-10T22:02:05.719133Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "                \n",
      "q1_0: ──────────\n",
      "                \n",
      "q1_1: ──────────\n",
      "                \n",
      "q1_2: ──────────\n",
      "      ┌───┐     \n",
      "q1_3: ┤ H ├──■──\n",
      "      └───┘  │  \n",
      "q1_4: ───────┼──\n",
      "           ┌─┴─┐\n",
      "q1_5: ─────┤ X ├\n",
      "           └───┘\n"
     ]
    }
   ],
   "source": [
    "# Create the actual circuit \n",
    "q2 = QuantumRegister(6)\n",
    "bell = QuantumCircuit(q2)\n",
    "bell.h(q2[3])\n",
    "bell.cx(q2[3], q2[5])\n",
    "print(bell)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here we are going to generate and run the state tomography circuits. By only passing in the 2 registers we want to measure the state tomography will only run on that reduced $2^2$ Hilbert space. However, if we pass the whole register in the state tomography module will try and fit the full $2^6$ space."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-10T22:02:05.962627Z",
     "start_time": "2019-12-10T22:02:05.729674Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Time taken: 0.3742101192474365\n"
     ]
    }
   ],
   "source": [
    "# Generate circuits and run on simulator\n",
    "t = time.time()\n",
    "\n",
    "# Generate the state tomography circuits.\n",
    "qst_bell = state_tomography_circuits(bell, [q2[3], q2[5]])\n",
    "\n",
    "# Execute\n",
    "job = qiskit.execute(qst_bell, Aer.get_backend('qasm_simulator'), shots=5000)\n",
    "print('Time taken:', time.time() - t)\n",
    "\n",
    "# Fit result\n",
    "tomo_fitter_bell = StateTomographyFitter(job.result(), qst_bell)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The fitter will output a density matrix ordered according to how we passed in the registers to ``state_tomography_circuits``. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-10T22:02:06.222354Z",
     "start_time": "2019-12-10T22:02:05.964786Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "State Fidelity: F = 0.99796\n"
     ]
    }
   ],
   "source": [
    "# Perform the tomography fit\n",
    "# which outputs a density matrix\n",
    "rho_fit_bell = tomo_fitter_bell.fit(method='lstsq')\n",
    "F_bell = qi.state_fidelity(rho_fit_bell, target_state_bell)\n",
    "print('State Fidelity: F = {:.5f}'.format(F_bell))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Repeat the Example with Measurement Noise"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-10T22:02:07.149325Z",
     "start_time": "2019-12-10T22:02:06.224483Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "State fidelity (no correction): F = 0.56463\n",
      "State fidelity (w/ correction): F = 0.98752\n"
     ]
    }
   ],
   "source": [
    "#Add measurement noise\n",
    "noise_model = noise.NoiseModel()\n",
    "for qubit in range(6):\n",
    "    read_err = noise.errors.readout_error.ReadoutError([[0.75, 0.25],[0.1,0.9]])\n",
    "    noise_model.add_readout_error(read_err,[qubit])\n",
    "    \n",
    "#generate the calibration circuits\n",
    "meas_calibs, state_labels = mc.complete_meas_cal(qubit_list=[3,5])\n",
    "\n",
    "backend = Aer.get_backend('qasm_simulator')\n",
    "job_cal = qiskit.execute(meas_calibs, backend=backend, shots=15000, noise_model=noise_model)\n",
    "job_tomo = qiskit.execute(qst_bell, backend=backend, shots=15000, noise_model=noise_model)\n",
    "\n",
    "meas_fitter = mc.CompleteMeasFitter(job_cal.result(),state_labels)\n",
    "\n",
    "tomo_bell = StateTomographyFitter(job_tomo.result(), qst_bell)\n",
    "\n",
    "#no correction\n",
    "rho_bell = tomo_bell.fit(method='lstsq')\n",
    "F_bell = qi.state_fidelity(rho_bell, target_state_bell)\n",
    "print('State fidelity (no correction): F = {:.5f}'.format(F_bell))\n",
    "\n",
    "#correct data\n",
    "correct_tomo_results = meas_fitter.filter.apply(job_tomo.result(), method='least_squares')\n",
    "tomo_bell_mit = StateTomographyFitter(correct_tomo_results, qst_bell)\n",
    "rho_fit_bell_mit = tomo_bell_mit.fit(method='lstsq')\n",
    "F_bell_mit = qi.state_fidelity(rho_fit_bell_mit, target_state_bell)\n",
    "print('State fidelity (w/ correction): F = {:.5f}'.format(F_bell_mit))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1-qubit process tomography example"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-10T22:04:09.537523Z",
     "start_time": "2019-12-10T22:04:09.363669Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{(('Zp',), ('X',)): {'0': 4000},\n",
       " (('Zp',), ('Y',)): {'0': 2013, '1': 1987},\n",
       " (('Zp',), ('Z',)): {'0': 1973, '1': 2027},\n",
       " (('Zm',), ('X',)): {'1': 4000},\n",
       " (('Zm',), ('Y',)): {'0': 1938, '1': 2062},\n",
       " (('Zm',), ('Z',)): {'0': 1979, '1': 2021},\n",
       " (('Xp',), ('X',)): {'0': 1991, '1': 2009},\n",
       " (('Xp',), ('Y',)): {'0': 1998, '1': 2002},\n",
       " (('Xp',), ('Z',)): {'0': 4000},\n",
       " (('Yp',), ('X',)): {'0': 1990, '1': 2010},\n",
       " (('Yp',), ('Y',)): {'1': 4000},\n",
       " (('Yp',), ('Z',)): {'0': 1997, '1': 2003}}"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Process tomography of a Hadamard gate\n",
    "q = QuantumRegister(1)\n",
    "circ = QuantumCircuit(q)\n",
    "circ.h(q[0])\n",
    "\n",
    "# Get the ideal unitary operator\n",
    "target_unitary = qi.Operator(circ)\n",
    "\n",
    "# Generate process tomography circuits and run on qasm simulator\n",
    "qpt_circs = process_tomography_circuits(circ, q)\n",
    "job = qiskit.execute(qpt_circs, Aer.get_backend('qasm_simulator'), shots=4000)\n",
    "\n",
    "# Extract tomography data so that counts are indexed by measurement configuration\n",
    "qpt_tomo = ProcessTomographyFitter(job.result(), qpt_circs)\n",
    "qpt_tomo.data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-10T22:04:09.602711Z",
     "start_time": "2019-12-10T22:04:09.540281Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Fit time: 0.008244037628173828\n",
      "Average gate fidelity: F = 0.99722\n"
     ]
    }
   ],
   "source": [
    "# Tomographic reconstruction\n",
    "t = time.time()\n",
    "choi_fit_lstsq = qpt_tomo.fit(method='lstsq')\n",
    "\n",
    "print('Fit time:', time.time() - t)\n",
    "print('Average gate fidelity: F = {:.5f}'.format(qi.average_gate_fidelity(choi_fit_lstsq, target=target_unitary)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1-qubit process tomography of two-qubit swap gate\n",
    "\n",
    "We will prepare qubit-0 and measure qubit-1 so the reconstructed channel should be an identity."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-10T22:04:09.748538Z",
     "start_time": "2019-12-10T22:04:09.605145Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{(('Zp',), ('X',)): {'0': 975, '1': 1025},\n",
       " (('Zp',), ('Y',)): {'0': 1009, '1': 991},\n",
       " (('Zp',), ('Z',)): {'0': 2000},\n",
       " (('Zm',), ('X',)): {'0': 1046, '1': 954},\n",
       " (('Zm',), ('Y',)): {'0': 989, '1': 1011},\n",
       " (('Zm',), ('Z',)): {'1': 2000},\n",
       " (('Xp',), ('X',)): {'0': 2000},\n",
       " (('Xp',), ('Y',)): {'0': 1016, '1': 984},\n",
       " (('Xp',), ('Z',)): {'0': 1003, '1': 997},\n",
       " (('Yp',), ('X',)): {'0': 969, '1': 1031},\n",
       " (('Yp',), ('Y',)): {'0': 2000},\n",
       " (('Yp',), ('Z',)): {'0': 992, '1': 1008}}"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Process tomography of a Hadamard gate\n",
    "q = QuantumRegister(2)\n",
    "circ = QuantumCircuit(q)\n",
    "circ.swap(q[0], q[1])\n",
    "\n",
    "# Generate process tomography circuits and run on qasm simulator\n",
    "# We use the optional prepared_qubits kwarg to specify that the prepared qubit was different to measured qubit\n",
    "qpt_circs = process_tomography_circuits(circ, q[1], prepared_qubits=q[0])\n",
    "job = qiskit.execute(qpt_circs, Aer.get_backend('qasm_simulator'), shots=2000)\n",
    "\n",
    "# Extract tomography data so that counts are indexed by measurement configuration\n",
    "qpt_tomo = ProcessTomographyFitter(job.result(), qpt_circs)\n",
    "qpt_tomo.data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Fit time: 0.008944988250732422\n",
      "Average gate fidelity: F = 0.99541\n"
     ]
    }
   ],
   "source": [
    "# Tomographic reconstruction\n",
    "\n",
    "t = time.time()\n",
    "choi_fit = qpt_tomo.fit(method='lstsq')\n",
    "print('Fit time:', time.time() - t)\n",
    "print('Average gate fidelity: F = {:.5f}'.format(qi.average_gate_fidelity(choi_fit)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Advances examples"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Generating and fitting random states\n",
    "\n",
    "We now test the functions on the state generated by a circuit consisting of a layer of random single qubit unitaries u3."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-10T22:02:07.158424Z",
     "start_time": "2019-12-10T22:02:07.151860Z"
    }
   },
   "outputs": [],
   "source": [
    "def random_u_tomo(nq, shots):\n",
    "    \n",
    "    def rand_angles():\n",
    "        return tuple(2 * np.pi * np.random.random(3) - np.pi)\n",
    "    q = QuantumRegister(nq)\n",
    "    circ = QuantumCircuit(q)\n",
    "    for j in range(nq):\n",
    "        circ.u(*rand_angles(), q[j])\n",
    "    target_state = qi.Statevector.from_instruction(circ)\n",
    "    \n",
    "    qst_circs = state_tomography_circuits(circ, q)\n",
    "    job = qiskit.execute(qst_circs, Aer.get_backend('qasm_simulator'),\n",
    "                         shots=shots)\n",
    "    tomo_data = StateTomographyFitter(job.result(), qst_circs)\n",
    "    rho_fit = tomo_data.fit(method='lstsq')\n",
    "    \n",
    "    print('F = {:.5f}'.format(qi.state_fidelity(rho_fit, target_state)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-10T22:02:10.608393Z",
     "start_time": "2019-12-10T22:02:07.162333Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Random single-qubit unitaries: set 0\n",
      "F = 0.99913\n",
      "Random single-qubit unitaries: set 1\n",
      "F = 0.99580\n",
      "Random single-qubit unitaries: set 2\n",
      "F = 0.99601\n",
      "Random single-qubit unitaries: set 3\n",
      "F = 0.98930\n",
      "Random single-qubit unitaries: set 4\n",
      "F = 0.99547\n"
     ]
    }
   ],
   "source": [
    "for j in range(5):\n",
    "    print('Random single-qubit unitaries: set {}'.format(j))\n",
    "    random_u_tomo(3, 5000)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5-Qubit Bell State"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-10T22:02:18.551117Z",
     "start_time": "2019-12-10T22:02:10.612471Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Time taken: 7.226781845092773\n"
     ]
    }
   ],
   "source": [
    "# Create a state preparation circuit\n",
    "q5 = QuantumRegister(5)\n",
    "bell5 = QuantumCircuit(q5)\n",
    "bell5.h(q5[0])\n",
    "for j in range(4):\n",
    "    bell5.cx(q5[j], q5[j + 1])\n",
    "\n",
    "# Get ideal output state\n",
    "target_state_bell5 = qi.Statevector.from_instruction(bell5)\n",
    "\n",
    "# Generate circuits and run on simulator\n",
    "t = time.time()\n",
    "qst_bell5 = state_tomography_circuits(bell5, q5)\n",
    "job = qiskit.execute(qst_bell5, Aer.get_backend('qasm_simulator'), shots=5000)\n",
    "\n",
    "# Extract tomography data so that counts are indexed by measurement configuration\n",
    "tomo_bell5 = StateTomographyFitter(job.result(), qst_bell5)\n",
    "print('Time taken:', time.time() - t)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-10T22:02:22.223534Z",
     "start_time": "2019-12-10T22:02:18.553830Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Time taken: 3.6470580101013184\n",
      "State fidelity: F = 0.99430\n"
     ]
    }
   ],
   "source": [
    "t = time.time()\n",
    "rho_fit_bell5 = tomo_bell5.fit(method='lstsq')\n",
    "print('Time taken:', time.time() - t)\n",
    "print('State fidelity: F = {:.5f}'.format(qi.state_fidelity(rho_fit_bell5, target_state_bell5)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2-Qubit Conditional State Tomography "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In this example, we have a three-qubit system where one of the qubits will be an ancilla for performing state tomography, i.e. only perform tomography when the third qubit is in the state \"1\". The circuit is setup in such a way that after conditional tomography we will get a Bell state on the first two qubits.\n",
    "\n",
    "First make a 3Q GHZ state with no classical measurements."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-10T22:03:01.884883Z",
     "start_time": "2019-12-10T22:03:01.869330Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "       ┌───┐               \n",
      "q11_0: ┤ H ├──■────────────\n",
      "       └───┘┌─┴─┐          \n",
      "q11_1: ─────┤ X ├──■───────\n",
      "            └───┘┌─┴─┐┌───┐\n",
      "q11_2: ──────────┤ X ├┤ H ├\n",
      "                 └───┘└───┘\n"
     ]
    }
   ],
   "source": [
    "# Create the actual circuit \n",
    "q2 = QuantumRegister(3)\n",
    "ghz = QuantumCircuit(q2)\n",
    "ghz.h(q2[0])\n",
    "ghz.cx(q2[0], q2[1])\n",
    "ghz.cx(q2[1], q2[2])\n",
    "ghz.h(q2[2])\n",
    "print(ghz)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here we are going to generate and run the state tomography circuits. Only pass the registers we want to perform state tomography on. The code will generate a new classical register for only those measurements."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-10T22:03:01.903389Z",
     "start_time": "2019-12-10T22:03:01.888165Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "       ┌───┐                ░ ┌───┐┌─┐   \n",
      "q11_0: ┤ H ├──■─────────────░─┤ H ├┤M├───\n",
      "       └───┘┌─┴─┐           ░ ├───┤└╥┘┌─┐\n",
      "q11_1: ─────┤ X ├──■────────░─┤ H ├─╫─┤M├\n",
      "            └───┘┌─┴─┐┌───┐ ░ └───┘ ║ └╥┘\n",
      "q11_2: ──────────┤ X ├┤ H ├─░───────╫──╫─\n",
      "                 └───┘└───┘ ░       ║  ║ \n",
      "c10: 2/═════════════════════════════╩══╩═\n",
      "                                    0  1 \n"
     ]
    }
   ],
   "source": [
    "qst_ghz = state_tomography_circuits(ghz, [q2[0],q2[1]])\n",
    "print(qst_ghz[0])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now make a copy of this circuit (we will need it for the fitter) and make a new circuit with an ancilla measurement attached (this is what will be run):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-10T22:03:01.915062Z",
     "start_time": "2019-12-10T22:03:01.906411Z"
    }
   },
   "outputs": [],
   "source": [
    "#Make a copy without the ancilla register\n",
    "qst_ghz_no_anc = deepcopy(qst_ghz)\n",
    "ca = ClassicalRegister(1)\n",
    "for qst_ghz_circ in qst_ghz:\n",
    "    qst_ghz_circ.add_register(ca)\n",
    "    qst_ghz_circ.measure(q2[2],ca[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-10T22:03:02.335643Z",
     "start_time": "2019-12-10T22:03:01.919990Z"
    }
   },
   "outputs": [],
   "source": [
    "#Run in Aer\n",
    "job = qiskit.execute(qst_ghz, Aer.get_backend('qasm_simulator'), shots=10000)\n",
    "raw_results = job.result()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Before sending the results to the state tomography fitter we must strip the register for the Q2 measurement and only keep the results when that register is 1."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-10T22:03:02.348493Z",
     "start_time": "2019-12-10T22:03:02.337934Z"
    }
   },
   "outputs": [],
   "source": [
    "\n",
    "new_result = deepcopy(raw_results)\n",
    "\n",
    "for resultidx, _ in enumerate(raw_results.results):\n",
    "    old_counts = raw_results.get_counts(resultidx)\n",
    "    new_counts = {}\n",
    "    \n",
    "    #change the size of the classical register\n",
    "    new_result.results[resultidx].header.creg_sizes = [new_result.results[resultidx].header.creg_sizes[0]]\n",
    "    new_result.results[resultidx].header.clbit_labels = new_result.results[resultidx].header.clbit_labels[0:-1]\n",
    "    new_result.results[resultidx].header.memory_slots = 2\n",
    "    \n",
    "    for reg_key in old_counts:\n",
    "        reg_bits = reg_key.split(' ')\n",
    "        if reg_bits[0]=='1':\n",
    "            new_counts[reg_bits[1]]=old_counts[reg_key]\n",
    "\n",
    "        new_result.results[resultidx].data.counts = new_counts "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-10T22:03:02.381672Z",
     "start_time": "2019-12-10T22:03:02.350264Z"
    }
   },
   "outputs": [],
   "source": [
    "tomo_bell = StateTomographyFitter(new_result, qst_ghz_no_anc)\n",
    "# Perform the tomography fit\n",
    "# which outputs a density matrix\n",
    "rho_fit_bell = tomo_bell.fit(method='lstsq')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-10T22:03:02.390883Z",
     "start_time": "2019-12-10T22:03:02.383619Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0.502+0.j   ,  0.   +0.001j,  0.004+0.001j, -0.498-0.006j],\n",
       "       [ 0.   -0.001j,  0.001+0.j   , -0.001-0.j   , -0.002+0.j   ],\n",
       "       [ 0.004-0.001j, -0.001+0.j   ,  0.001+0.j   , -0.003+0.001j],\n",
       "       [-0.498+0.006j, -0.002-0.j   , -0.003-0.001j,  0.497+0.j   ]])"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.around(rho_fit_bell, 3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Gate set tomography"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1-Qubit gate set tomography Examples"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The main difference between gate set tomography and process tomography is that in gate set tomography, the input consists of a gate set basis: A set of gates that are both used in the initialization/measurement phase of the tomography, and are being reconstructed.\n",
    "\n",
    "Qiskit supplies a default gateset basis; in order to use this gateset basis in order to reconstruct another gate, this gate should be added to the basis. We use the following method to simplify the process:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "from qiskit.ignis.verification.tomography.basis import default_gateset_basis\n",
    "\n",
    "def collect_tomography_data(shots=10000,\n",
    "                            noise_model=None,\n",
    "                            gateset_basis='Standard GST'):\n",
    "    backend_qasm = Aer.get_backend('qasm_simulator')\n",
    "    circuits = gateset_tomography_circuits(gateset_basis=gateset_basis)\n",
    "    qobj = assemble(circuits, shots=shots)\n",
    "    result = backend_qasm.run(qobj, noise_model=noise_model).result()\n",
    "    fitter = GatesetTomographyFitter(result, circuits, gateset_basis)\n",
    "    return fitter\n",
    "\n",
    "def gate_set_tomography(gate, noise_model=None):\n",
    "    basis = default_gateset_basis()\n",
    "    basis.add_gate(gate)\n",
    "    fitter = collect_tomography_data(shots=10000, noise_model=noise_model, gateset_basis=basis)\n",
    "    result_gates = fitter.fit()\n",
    "    result_gate = result_gates[gate.name]\n",
    "    return Choi(result_gate)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Noiseless 1-qubit gate set tomography"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "fit time: 2.530395746231079\n",
      "Average gate fidelity: F = 1.00084\n"
     ]
    }
   ],
   "source": [
    "target_unitary = qi.Operator(HGate())\n",
    "t = time.time()\n",
    "channel_fit = gate_set_tomography(HGate())\n",
    "print('fit time:', time.time() - t)\n",
    "print('Average gate fidelity: F = {:.5f}'.format(qi.average_gate_fidelity(channel_fit, target_unitary)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-10T22:03:02.465096Z",
     "start_time": "2019-12-10T22:03:02.392599Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/cjwood/anaconda3/envs/qiskit-legacy/lib/python3.7/site-packages/ipykernel/ipkernel.py:287: DeprecationWarning: `should_run_async` will not call `transform_cell` automatically in the future. Please pass the result to `transformed_cell` argument and any exception that happen during thetransform in `preprocessing_exc_tuple` in IPython 7.17 and above.\n",
      "  and should_run_async(code)\n",
      "/Users/cjwood/anaconda3/envs/qiskit-legacy/lib/python3.7/site-packages/qiskit/tools/jupyter/__init__.py:134: RuntimeWarning: matplotlib can't be found, ensure you have matplotlib and other visualization dependencies installed. You can run '!pip install qiskit-terra[visualization]' to install it from jupyter\n",
      "  \"jupyter\", RuntimeWarning)\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<h3>Version Information</h3><table><tr><th>Qiskit Software</th><th>Version</th></tr><tr><td>Qiskit</td><td>0.22.0</td></tr><tr><td>Terra</td><td>0.15.2</td></tr><tr><td>Aer</td><td>0.6.1</td></tr><tr><td>Ignis</td><td>0.4.0</td></tr><tr><td>Aqua</td><td>0.7.5</td></tr><tr><td>IBM Q Provider</td><td>0.10.0</td></tr><tr><th>System information</th></tr><tr><td>Python</td><td>3.7.9 (default, Aug 31 2020, 07:22:35) \n",
       "[Clang 10.0.0 ]</td></tr><tr><td>OS</td><td>Darwin</td></tr><tr><td>CPUs</td><td>6</td></tr><tr><td>Memory (Gb)</td><td>32.0</td></tr><tr><td colspan='2'>Tue Nov 03 13:53:54 2020 EST</td></tr></table>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<div style='width: 100%; background-color:#d5d9e0;padding-left: 10px; padding-bottom: 10px; padding-right: 10px; padding-top: 5px'><h3>This code is a part of Qiskit</h3><p>&copy; Copyright IBM 2017, 2020.</p><p>This code is licensed under the Apache License, Version 2.0. You may<br>obtain a copy of this license in the LICENSE.txt file in the root directory<br> of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.<p>Any modifications or derivative works of this code must retain this<br>copyright notice, and modified files need to carry a notice indicating<br>that they have been altered from the originals.</p></div>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import qiskit.tools.jupyter\n",
    "%qiskit_version_table\n",
    "%qiskit_copyright"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.5"
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
